<?php

namespace app\commands;

use app\lib\VectorHelper;
use app\models\Audio;
use app\models\Record;
use app\models\User;
use yii\console\Controller;
use yii\console\Exception;
use yii\helpers\ArrayHelper;

class RecController extends Controller {
    public function actionRandom() {
        /** @var User[] $users */
    	$users = User::find()->all();
        /** @var Audio[] $audios */
        $audios = Audio::find()->all();

        Record::deleteAll([]);
        foreach ($users as $user) {
            $active = mt_rand(0, 1000);
            var_dump($active);
            foreach ($audios as $audio) {
                if(mt_rand(0, 1000) > $active) continue;

                $record = new Record();
                $record->audio_id = $audio->id;
                $record->user_id = $user->id;
                $record->read_times = floor(log(1000) - log(mt_rand(1,1000)));

                if($record->read_times>0) {
                    $record->listen_times = floor($record->read_times - log(mt_rand(1,exp($record->read_times))));
                    if($record->listen_times>0) {
                        $time = 0;
                        $totalTime = strtotime($audio->length) - strtotime('0:0');
                        for($i=0; $i<$record->listen_times; $i++) {
                            $time = floor(max($time, $totalTime * pow(mt_rand(0, 1000) / 1000, 2)));
                        }
                        $record->listen_time = date('H:i:s', $time);

                        $record->prase = false;
                        if($time > $totalTime * 0.3) {
                            $record->prase = mt_rand(0, 1000) < 400;
                        }
                        $record->collect = false;
                        if($time > $totalTime * 0.5) {
                            $record->collect = mt_rand(0, 1000) < 600;
                        }
                    }
                    if(!$record->save()) {
                        var_dump($record->errors);
                    }
                }
            }

        }
    }

    //计算权重
    public function actionWeight() {
        $recordQuery = Record::find();

        foreach ($recordQuery->each() as $record) {
            /** @var Record $record */

            // TODO 权重计算方式 下面还有一块有
            $record->weight =
                $record->read_times * 1 +
                $record->listen_times * 5 +
                (strtotime($record->listen_time) - strtotime('0:0') + 1) / (strtotime($record->audio->length) - strtotime('0:0') + 1) * 20 +
                $record->prase * 10 +
                $record->collect * 15;
            $record->weight = round($record->weight, 4);

            if(!$record->save()) {
                var_dump($record->errors);
            }
        }
    }

    //将权重变为向量
    public function actionUserVector() {
        /** @var User[] $users */
        $users = User::find()->all();

        foreach ($users as $user) {
            /** @var Record[] $records */
            $records = Record::find()->where(['user_id'=>$user->id])->all();
            $vector = [];
            foreach($records as $record) {
                $vector[$record->audio_id] = $record->weight;
            }
            $user->vector_str = serialize($vector);

            if(!$user->save()) {
                var_dump($user->errors);
            }
        }
    }

    public function actionCal($userId) {
        /** @var User[] $users */
        $users = User::find()->all();
        /** @var Audio[] $audios */
        $audios = Audio::find()->all();
        $maxAudioId = $audios[count($audios)-1]->id;

        /** @var Record[] $avgRecords */
        $avgRecords = Record::findBySql('select audio_id,AVG(collect) as collect,AVG(time_to_sec(listen_time)) as listen_time,AVG(listen_times) as listen_times,AVG(prase) as prase,AVG(read_times) as read_times from record GROUP BY audio_id;')->indexBy('audio_id')->all();
        foreach ($avgRecords as $record) {
            // TODO 权重计算方式
            $record->weight =
                $record->read_times * 1 +
                $record->listen_times * 5 +
                ($record->listen_time + 1) / (strtotime($record->audio->length) - strtotime('0:0') + 1) * 20 +
                $record->prase * 10 +
                $record->collect * 15;
            $record->weight = round($record->weight, 4);
        }

        /** @var User $targetUser */
        $targetUser = User::findOne($userId);
        if(!$targetUser) {
            throw new Exception('user not exist');
        }
        $targetVector = $targetUser->vector;
        foreach ($avgRecords as $record) {
            // 如果对应audio的关注度为0,则使用平均水平
            if(!isset($targetVector[$record->audio_id]) || $targetVector[$record->audio_id] == 0) {
                $targetVector[$record->audio_id] = $record->weight;
            }
        }
        foreach ($users as $user) {
            if($user->id == $targetUser->id) {
                $user->sex = 0;
                continue;
            }
            $user->sex = VectorHelper::getCosine($user->vector, $targetVector, $maxAudioId);
        }

        ArrayHelper::multisort($users, 'sex', SORT_DESC);

        echo "最相近的用户及其喜好:\nusr\\au\t";
        for($inc = 1; $inc<=$maxAudioId; $inc++) echo $inc, "\t";
        echo "\n";


        // TODO 选择N个喜好相近的用户
        $stardUserCount = 10;


//        $maxAudioId = 3;
        $userCount = 0;
        $stardVector = array_fill(1, $maxAudioId, 0);
        foreach($users as $user) {
            if($userCount++ == $stardUserCount) {
                break;
            }
            echo $user->id, "\t";
            for($inc = 1; $inc<=$maxAudioId; $inc++) echo isset($user->vector[$inc]) ? $user->vector[$inc] : 0, "\t";
            echo "\n";

            for($i = 1; $i <= $maxAudioId; $i++){
                $stardVector[$i] += (isset($user->vector[$i]) ? $user->vector[$i] : 0);
//                var_dump($stardVector);
            }
        }

        // 计算可以推荐的内容
        $recVector = [];
        for($i = 1; $i <= $maxAudioId; $i++){
            $stardVector[$i] /= $stardUserCount;
            $stardVector[$i] = round($stardVector[$i], 4);

            $recVector[$i] = $stardVector[$i] - (isset($targetUser->vector[$i]) ? $targetUser->vector[$i] : 0);
        }

        echo "猜测喜好\t", join("\t", $stardVector), "\n";

        echo "全站平均\t";
        $avgVector = ArrayHelper::getColumn($avgRecords, 'weight');
        for($inc = 1; $inc<=$maxAudioId; $inc++) echo isset($avgVector[$inc]) ? $avgVector[$inc] : 0, "\t";
        echo "\n";

//        echo "当前补全\t";
//        for($inc = 1; $inc<=$maxAudioId; $inc++) echo isset($targetVector[$inc]) ? $targetVector[$inc] : 0, "\t";
//        echo "\n";

        echo "当前喜好\t";
        for($inc = 1; $inc<=$maxAudioId; $inc++) echo isset($targetUser->vector[$inc]) ? $targetUser->vector[$inc] : 0, "\t";
        echo "\n";

        echo "差值推荐\t", join("\t", $recVector), "\n";


        arsort($recVector, SORT_ASC);
        var_dump($recVector);




    }
}
